可变参数列表源码的剖析

您所在的位置:网站首页 my bolg作文 可变参数列表源码的剖析

可变参数列表源码的剖析

#可变参数列表源码的剖析| 来源: 网络整理| 查看: 265

在某些情况下我们希望函数参数的个数可以根据实际需要来定,所以C语言中就提供了一种长度不确定的参数,形如:“…”,C++语言也继承了这一语言特性。在采用ANSI标准形式时,参数个数可变的函数的原型是:

type func name(typepara1,typepara2,…);

这种形式至少需要一个普通的形式参数,后面的省略号(…)不能省去,它是函数原型必不可少的一部分。典型的例子有大家熟悉的printf()、scanf()函数。

下面我们以print函数为例,如下所示的就是printf()的原型:

int printf( const char* format , [argument] … ); 一丶printf功能: printf函数是格式化输出函数,一般用于向标准输出设备按规定格式输出信息。 二丶利用可变参数列表模拟实现printf: 1.分析printf函数

printf(“Hello bit!\n”); printf(“%s”,”Welcome to my bolg\n”); printf(“hell%c\n”,’o’);

我们发现,printf函数的参数是不确定的,传参的地方必须使用其他东西

2.解决方法 利用stdarg宏来解决可变参数问题 头文件:stdarg.h

va_list; type va_arg( va_list arg_ptr, type ); void va_end( va_list arg_ptr ); void va_start( va_list arg_ptr, prev_param );

也许这些已经为大家所熟知,但是可变参数的实现原理却是C语言中比较难理解的一部分。 在标准C语言中定义了一个头文件#include中,专门用来对付可变参数列表,其 中,包含了一个…va_list…的typedef声明和一组宏定义va_start、va_arg、va_end,如下所示: Vs2013中的stdarg.h 这里写图片描述 这里写图片描述 说明: va_list 是用宏定义的标识符,是指向字符类型的指针 va_start(ap,v) 取出va_list 定义的变量的地址,并加上可变元素的数目 va_arg(ap,t) 每次取指针指向的内容,并在宏的内部将指针后移 va_end(ap) 将原指针指向空,以防止野指针的出现

定义_INTSIZEOF(n)是为了使系统内存对齐;va_start(ap,v)使ap指向第一个可变参数在堆栈中的地址,va_arg(ap,t)使ap指向下一个可变参数的堆栈地址,并用*取得该地址的内容;最后变参获取完毕,通过va_end(ap)让ap不再指向堆栈。

三丶print函数实用

#include #include #include void print(char* val, ...){ char*c = NULL; va_list arg; va_start(arg, val); while (*val != '\0'){ //val指向“val,s ccc” if (*val == 'c'){ putchar(va_arg(arg, char)); } else if (*val == 's'){ puts(va_arg(arg, char*)); } else putchar(*val); ++val; } va_end(arg); } int main(){ print("s ccc \n", "hello", 'b', 'i', 't',100); system("pause"); return 0; } 可变参数使用注意:

由于将va_start、va_arg、va_end定义成了宏,可变参数的类型和个数在该函数中完全由程序代码控制,并不能智能地进行识别,所以导致编译器对可变参数的函数原型检查不够严格,难于查错,不利于写出高质量的代码。

参数个数可变具有很多的优点,为程序员带来了很多的方便,但是上面C风格的可变参数却存在着如下的缺点: (1)缺乏类型检查,类型安全性无从谈起。“省略号的本质是告诉编译器‘关闭所有检查,从此由我接管,启动reinterpret_cast’”,强制将某个类型对象的内存表示重新解释成另外一种对象类型,这是违反“类型安全性”的,是大忌。 (2)因为禁用了语言类型检查功能,所以在调用时必须通过其他方式告诉函数所传递参数的类型,以及参数个 数,就像很多人熟知的printf()函数中的格式字符串char*format。这种方式需要手动协调,既易出错,又不安 全,上面的代码片段已经充分说明了这一点。 (3)不支持自定义数据类型。自定义数据类型在C++中占有较重的地位,但是长参数只能传递基本的内置类型。

可变参数总结:

编译器对可变参数函数的原型检查不够严格,所以容易引起问题,难于查错,不利于写出高质量的代码。所以应当尽量避免使用C语言方式的可变参数设计。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3